namespace MessageBroker.Server

import System
import System.Collections
import MessageBroker

class Broker(IBroker): 
"""Description of MyClass."""
	
	[property(SharedQueues)]
	sharedQueues as Hashtable
	
	[property(Subscriptions)]
	subscriptions = Hashtable()
	
	def constructor():
		pass
		
	public def CreateSubscription(subscriptionName as string, subscriber as string) as Subscription:
		subscript = Subscription(Name: subscriptionName, Referral: subscriber)
		lock subscriptions:
			subscriptions.Add(subscript.Key(), subscript)
		return subscript
		
	private def InternalSend(destination as string, message as Message):	
		for sharedQueue as SharedQueue in SharedQueues.Values:
			if (sharedQueue.Name.Equals(destination)):
				lock sharedQueue.Messages:
					sharedQueue.Messages.Enqueue(message)
				return			
		for subscript as Subscription in subscriptions.Values:
			if (subscript.Name.Equals(destination)):
				lock subscript.Messages:
					subscript.Messages.Enqueue(message)

	public def Send(destination as string, message as Message):
		InternalSend(destination, message) //sync
			
	public def Receive(destination as string, subscriber as string) as Message:
		queueStore = subscriptions[Subscription.Key(destination, subscriber)] as QueueStore
		if queueStore == null: 
			queueStore = sharedQueues[destination] as QueueStore
		if (queueStore == null):
			raise Exception("${subscriber} did not subscribe to queue ${destination} or ${destination} does not exist")
		else:
			try:
				lock queueStore.Messages:
					return queueStore.Messages.Dequeue()
			except:
				pass
		
	private def checkAndAdd2result(queueStore as QueueStore, result as IList, howMany as int):
		try:
			lock queueStore.Messages:
				remaining = howMany - result.Count
				remaining = Math.Min(remaining, queueStore.Messages.Count)
				for n in range(result.Count, remaining):
					msg = queueStore.Messages.Dequeue()
					result.Add(msg)
		except:
			pass

	public def Receive(destination as string, subscriber as string, howMany as int) as IList:
		queueStore = subscriptions[Subscription.Key(destination, subscriber)] as QueueStore 
		if queueStore == null: 
			queueStore = sharedQueues[destination] as QueueStore
		if (queueStore == null):
			raise Exception("${subscriber} did not subscribe to queue ${destination} or ${destination} does not exist")
		else:
			result = List()
			checkAndAdd2result(queueStore, result, howMany)
			return result		

	private def queueStoresForSubscriber(subscriber as string) as IList:
		result = List()
		for queueStore in sharedQueues.Values:
			result.Add(queueStore)
		for subscript as Subscription in subscriptions.Values:
			if (subscript.Referral.Equals(subscriber)):
				result.Add(subscript)
		return result

	public def Receive(subscriber as string, howMany as int) as IList:
		result = List()
		stores = queueStoresForSubscriber(subscriber)
		for queueStore as QueueStore in stores:
			checkAndAdd2result(queueStore, result, howMany)
		return result
		
	def MassiveSend(messages as IList, subscriber as string):
		for message as Message in messages:
			Send(message.SentTo, message)
